
package algo_lignes_sites.data.pre_trt.pre_trt_path.simplif_topo;

import algo_lignes_sites.data.junction.A_Junction;
import algo_lignes_sites.data.junction.JunctionREF;
import algo_lignes_sites.data.path.A_Path;
import algo_lignes_sites.data.path.PathREF;
import commons.logs.Logger;
import commons.utils.primitive_geom.Point_d;
import commons.utils.primitive_geom.Rect_d;
import commons.utils.primitive_geom.Segment_bound;
import commons.utils.primitive_geom.Segment_d;
import gnu.trove.set.hash.THashSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;


public class Pattern_nPtMultTo1 {

	private enum PERMISSIVITE {TRES, MOYENNEMENT, PEU, TRES_PEU}
//	private static PERMISSIVITE permissivite = PERMISSIVITE.TRES; // inexploitable car trop laid
//	private static PERMISSIVITE permissivite = PERMISSIVITE.MOYENNEMENT; // pas tres beau, réservé aux zones très denses
//	private static PERMISSIVITE permissivite = PERMISSIVITE.PEU; // le plus acceptable en zones denses
	private static PERMISSIVITE permissivite = PERMISSIVITE.TRES_PEU; // ne fait pas grand chose mais esthetique, adapté aux zones non denses pour des aspects cosmétiques (lignes qui se tortillent etc.)


	static int PATTERN_3_1 = 0;
	static int PATTERN_2_1 = 1;
	private static int typePattern;
	
	//cf. commentaire de l'init
	private static HashMap<PathREF, Rect_d> mapPathInitialRect;
	
	// petite optim pour ne pas refaire les traitements inutilement
	private static THashSet<String> setTrioNotWorking;
	// petite optim pour ne pas refaire les traitements inutilement
	private static THashSet<String> setDuoNotWorking;
	
	static boolean traite(int typePattern) {
		Pattern_nPtMultTo1.typePattern = typePattern;
		if (typePattern == PATTERN_3_1)
			Logger.log_DEBUG1("##### BOUCLE PATTERN 3PtMultTo1 #####");
		else
			Logger.log_DEBUG1("##### BOUCLE PATTERN 2PtMultTo1 #####");
		
		// le spi path est long a realimenter, on va se contenter de supprimer les path lors de chaque realisation de pattern
		// pour ce qui est des path qui ont ete deforme par le pettern, cette deformation est minime et compensee par des recherche sur des rect plus larges
		SimplifTopo.spiPath.clear();
		SimplifTopo.spiPath.addObjects (SimplifTopo.vPathREF);
		
		// comme on ne met pas a jour le SPI pour les path, et qu'on appelle SPI.removeobject(), comme leur rect emglobant
		//  peut avoir ete legerement modifie, le SPI ne pourra pas les supprimer correctement s'ils ne se trouvent
		//  plus dans les memes cases (un assert le detecte)
		// pour ces raisons chaque path modifie se voit stocker son rect englobant initial mis dans une map
		//   ie le rect qui sert lors de l'alimentation initiale du SPI
		// ainsi, si le path doit etre supprime dans une iteration ulterieure de ce pattern
		//  on saura dire au SPI sur quel rect il doit rechercher le path pour la suppression
		mapPathInitialRect = new HashMap<PathREF, Rect_d>();
		
		// Pour les points multiple, ils sont gérés avec un spi dans la classe SimplifTopo
		SimplifTopo.reinitDataPtMultiple();

		boolean bAtLeatOneRealisation = false;
		
		boolean bReBoucle = true;
		while (bReBoucle) {
			bReBoucle = false;
			Logger.log_DEBUG1("~~~~ sous-boucle PATTERN nPtMultTo1 ~~~~");
			setTrioNotWorking = new THashSet<String>(512);
			setDuoNotWorking = new THashSet<String>(1024);
			
			
			int nbJ = SimplifTopo.vPtMultiple.size();
			for (int i=0; i<nbJ; i++) {
				JunctionREF j = SimplifTopo.vPtMultiple.get(i);
				assert (j.isIntersectOrConnect3());
				if (etudiePattern_AutourDe(j, setTrioNotWorking)) {

					bReBoucle = true;
					bAtLeatOneRealisation = true;

					// On continue le parcours mais la taille du vecteur de junction a change ...
					nbJ = SimplifTopo.vPtMultiple.size();
				}
			}
		}
		return bAtLeatOneRealisation;
	}
	
	
	
	private static boolean etudiePattern_AutourDe(JunctionREF j, THashSet<String> setTrioNotWorking) {
		ArrayList<JunctionREF> vPtMult_inZST = SimplifTopo.getPtMultiple_inZST(j);
		int nbPtMultiple = vPtMult_inZST.size();
		
		
		Logger.log_DEBUG2("## Test sur un bloc de " + nbPtMultiple + " pt multiples");
		
		// Test de toutes les combinaisons 3 par 3 (ou 2 par 2)
		JunctionREF j1, j2, j3;
		double largZST; 
	
		if (typePattern == PATTERN_3_1) {
			if (nbPtMultiple<=2) return false;
			
			for (int i1=0 ; i1<nbPtMultiple ; i1++) {
				j1 = vPtMult_inZST.get(i1);
				largZST = j1.getLargestPathContenant_withDissy()*SimplifTopo.params.factor_SimplifTopo;

				for (int i2=i1+1 ; i2<nbPtMultiple ; i2++) {
					j2 = vPtMult_inZST.get(i2);
					largZST = Math.max(largZST, j2.getLargestPathContenant_withDissy()*SimplifTopo.params.factor_SimplifTopo);

					for (int i3=i2+1 ; i3<nbPtMultiple ; i3++) {
						j3 = vPtMult_inZST.get(i3);
						largZST = Math.max(largZST, j3.getLargestPathContenant_withDissy()*SimplifTopo.params.factor_SimplifTopo);

						// optim
						String idTrio = getIdForTrio(j1, j2, j3);
						if (setTrioNotWorking.contains(idTrio))
							continue;

						SimplifTopo.nbPatternTeste_3PtMultTo1++;
						if (etudiePattern (j1, j2, j3, largZST)) {
							// Le pattern a fonctionné et la simplification topo a été réalisée
							// On ne peut pas tester les autres combinaisons car certaines junctions ont disparu !
							SimplifTopo.nbPatternRealise_3PtMultTo1 ++;
							return true;
						} else {
							// Le pattern n'a pas fonctionne et aucune simplif topo n'a ete realisee, on continue le parcours
							setTrioNotWorking.add(idTrio);
						}
					}
				}
			}
		} else {
			// PATERN 2 -> 1
			if (nbPtMultiple<=1) return false;
			
			for (int i1=0 ; i1<nbPtMultiple ; i1++) {
				j1 = vPtMult_inZST.get(i1);
				largZST = j1.getLargestPathContenant_withDissy()*SimplifTopo.params.factor_SimplifTopo;

				for (int i2=i1+1 ; i2<nbPtMultiple ; i2++) {
					j2 = vPtMult_inZST.get(i2);
					largZST = Math.max(largZST, j2.getLargestPathContenant_withDissy()*SimplifTopo.params.factor_SimplifTopo);
					
					// optim
					String idDuo = getIdForDuo(j1, j2);
					if (setDuoNotWorking.contains(idDuo))
						continue;

					SimplifTopo.nbPatternTeste_2PtMultTo1++;
					if (etudiePattern (j1, j2, null, largZST)) {
						// Le pattern a fonctionné et la simplification topo a été réalisée
						// On ne peut pas tester les autres combinaisons car certaines junctions ont disparu !
						SimplifTopo.nbPatternRealise_2PtMultTo1 ++;
						return true;
					} else {
						// Le pattern n'a pas fonctionne et aucune simplif topo n'a ete realisee, on continue le parcours
						setDuoNotWorking.add(idDuo);
					}
				}
			}
		}
		
		// Arrives la, le pattern n'a jamais fonctionne autour de j
		return false;
	}

	
	private static boolean etudiePattern(JunctionREF j1, JunctionREF j2, JunctionREF j3, double largZST) {
		// Barycentre des 3/2 J
		Point_d ptG;
		
		if (typePattern==PATTERN_3_1) {
			Logger.log_DEBUG2("Test PATTERN 3 PT MULTIPLE -> 1 : " + j1.getMainPathContenant() + " - " + j2.getMainPathContenant() + " - " + j3.getMainPathContenant());
			ptG = new Point_d ( (j1.x + j2.x + j3.x)/3 , (j1.y + j2.y + j3.y)/3 );

			// Les 3 pt multiple doivent satisfaire les conditions :
			//  a) être reliés 2 à 2 par au minimum 1 Path
			//  b) chacun des liens reliant 2 ptMultiple ne doit être constitué que de junction STANDARD ou bien du 3eme pt multiple
			//  c) toutes ces junctions STANDARD ne doivent pas s'éloigner du barycentre(j1,j2,j3) de plus de la largeur de ZST
			// => on doit donc avoir une sorte de "triangle" reliant les 3 ptMultiple
			boolean bOK;
			bOK = doesJunctionSatisfyPattern(j1, j2, ptG, largZST, j3);
			if (bOK) bOK = doesJunctionSatisfyPattern(j1, j3, ptG, largZST, j2);
			if (bOK) bOK = doesJunctionSatisfyPattern(j2, j3, ptG, largZST, j1);
			if (!bOK) {
				Logger.log_DEBUG2(" -> KO");
				return false;
			}
			
			// Récupération de la liste de tous les path concernés par la simplification
			//  c'est tous les path qui passent par les 3 pt multiples
			THashSet<PathREF> setPathSimplifies = new THashSet<PathREF>();
			setPathSimplifies.addAll((ArrayList)j1.getVPathContenant());
			setPathSimplifies.addAll((ArrayList)j2.getVPathContenant());
			setPathSimplifies.addAll((ArrayList)j3.getVPathContenant());


			// Derniere condition a respecter pour ce pattern :
			// Chaque path doit etre compatible avec la fusion operee par le pattern
// ancienne methode trop restrictive
//			//  notamment, il ne faut pas que 2 path qui avant ne se croisaient pas se retrouvent intersecter
//			//  a la fin du pattern
//			bOK = true;
//			for (PathREF path : setPathSimplifies)
//				if (!isPathCompatibleWithPattern(path, j1, j2, j3)) {
//					Logger.log_DEBUG2(" => KO : le path " + path + " n'est pas compatible avec le pattern");
//					//return false;
//					bOK = false;
//					break;
//				}
//			if (bOK) return false;
			
			if (!arePathCompatibleWithPattern(permissivite, j1, j2, j3)) {
				Logger.log_DEBUG2(" => KO : structure topo des path incompatible avec le pattern");
				return false;
			}

			ArrayList<Segment_bound> vSegmentAdded = null;
			HashMap<PathREF,SimplifTopo.PortionPath> mapPortionDeleted = null;
			int numStrategie = 0;
			boolean bTryAnotherStrategie = true;
			bOK = false;
			while (bTryAnotherStrategie) {
				Logger.log_DEBUG2("Test des intersections avec la strategie num " + numStrategie);
				// num 0 = ptG standar au centre de gravite des 3 pt multiples
				if (numStrategie == 1)
					ptG = new Point_d ( (10*j1.x + j2.x + j3.x)/12 , (10*j1.y + j2.y + j3.y)/12 );
				else if (numStrategie == 2)
					ptG = new Point_d ( (j1.x + 10*j2.x + j3.x)/12 , (j1.y + 10*j2.y + j3.y)/12 );
				else if (numStrategie == 3)
					ptG = new Point_d ( (j1.x + j2.x + 10*j3.x)/12 , (j1.y + j2.y + 10*j3.y)/12 );

				// Pour chacun de ces path, on va leur demander la liste des segments qui vont être supprimés
				//  et la liste des segments qui vont être créés
				// => va servir à déterminer si de nouvelles intersections vont être créées par la simplif topo
				vSegmentAdded = new ArrayList<Segment_bound>();
				mapPortionDeleted = new HashMap<PathREF,SimplifTopo.PortionPath>();
				for (PathREF path : setPathSimplifies) 
					computeNewAndDeletedSegment(path, j1, j2, j3, ptG, vSegmentAdded, mapPortionDeleted);

				// TODO_COMPLIQUE car liste des segments ajoutés change; OPTIM : remonter ca au dessus du while de strategie
				// Récupération de tous les path qui pourraient creer une éventuelle nouvelle intersection
				Rect_d rectRecherchePath = new Rect_d(ptG); 
				for (Segment_d seg : vSegmentAdded)
					rectRecherchePath.extendToSeg(seg);
				rectRecherchePath.expand(2*largZST, 2*largZST);// on grossi pas mal le rect compenser le fait que le SPI Path n'est pas mis a jour entre chaque realisation de pattern
				ArrayList<PathREF> vPathProche = (ArrayList) SimplifTopo.spiPath.getObjectsThatMayIntersectWith(rectRecherchePath);

				boolean bNewIntersect = SimplifTopo.isThereNewIntersection(vPathProche, vSegmentAdded, mapPortionDeleted);
				if (bNewIntersect) {
					numStrategie++;
					if (numStrategie>=4) break;
					continue;
				} else {
					bOK = true;
					break;
				}
			}

			if (!bOK) {
				Logger.log_DEBUG2(" => KO : toutes les strategies creent de nouvelles intersections ...");
				return false;
			}
			// Ici, tout est OK : on va realiser la simplification
			Logger.log_DEBUG1(" => OK pour " + j1.getMainPathContenant() + " - " + j2.getMainPathContenant() + " - " + j3.getMainPathContenant());
			realisePattern(j1, j2, j3, ptG, setPathSimplifies, mapPortionDeleted);

			assert(!SimplifTopo.vPtMultiple.contains(j1) && !SimplifTopo.vPtMultiple.contains(j2) && !SimplifTopo.vPtMultiple.contains(j3));
			return true;
			
		} else {
			// PATERN 2 -> 1
			Logger.log_DEBUG2("Test PATTERN 2 PT MULTIPLE -> 1 : " + j1.getMainPathContenant() + " - " + j2.getMainPathContenant());
			
			ptG = new Point_d ( (j1.x + j2.x)/2 , (j1.y + j2.y)/2 );
			
			// Les 2 pt multiple doivent satisfaire le meme genre de conditions que pour 3->1
			boolean bOK;
			bOK = doesJunctionSatisfyPattern(j1, j2, ptG, largZST, null);
			if (!bOK) {
				Logger.log_DEBUG2(" -> KO");
				return false;
			}
			
			// Récupération de la liste de tous les path concernés par la simplification
			//  c'est tous les path qui passent par les 2 pt multiples
			THashSet<PathREF> setPathSimplifies = new THashSet<PathREF>();
			setPathSimplifies.addAll((ArrayList)j1.getVPathContenant());
			setPathSimplifies.addAll((ArrayList)j2.getVPathContenant());


			// Derniere condition a respecter pour ce pattern :
			// Chaque path doit etre compatible avec la fusion operee par le pattern
// ancienne methode trop restrictive
//			bOK = true;
//			for (PathREF path : setPathSimplifies)
//				if (!isPathCompatibleWithPattern(path, j1, j2, null)) {
//					Logger.log_DEBUG2(" => KO : le path " + path + " n'est pas compatible avec le pattern");
//					//return false;
//					bOK = false;
//					break;
//				}
//			if (bOK) return false;
			
			if (!arePathCompatibleWithPattern(permissivite, j1, j2, null)) {
				Logger.log_DEBUG2(" => KO : structure topo des path incompatible avec le pattern");
				return false;
			}
			
			
			ArrayList<Segment_bound> vSegmentAdded = null;
			HashMap<PathREF,SimplifTopo.PortionPath> mapPortionDeleted = null;
			int numStrategie = 0;
			boolean bTryAnotherStrategie = true;
			bOK = false;
			while (bTryAnotherStrategie) {
				Logger.log_DEBUG2("Test des intersections avec la strategie num " + numStrategie);
				// num 0 = ptG standard au centre de gravite des 3 pt multiples
				if (numStrategie == 1)
					ptG = new Point_d ( (10*j1.x + j2.x)/11 , (10*j1.y + j2.y)/11 );
				else if (numStrategie == 2)
					ptG = new Point_d ( (j1.x + 10*j2.x)/11 , (j1.y + 10*j2.y)/11 );

				// Pour chacun de ces path, on va leur demander la liste des segments qui vont être supprimés
				//  et la liste des segments qui vont être créés
				// => va servir à déterminer si de nouvelles intersections vont être créées par la simplif topo
				vSegmentAdded = new ArrayList<Segment_bound>();
				mapPortionDeleted = new HashMap<PathREF,SimplifTopo.PortionPath>();
				for (PathREF path : setPathSimplifies) 
					computeNewAndDeletedSegment(path, j1, j2, null, ptG, vSegmentAdded, mapPortionDeleted);

				// // TODO_COMPLIQUE car liste des segments ajoutés change; OPTIM : remonter ca au dessus du while de strategie
				// Récupération de tous les path qui pourraient creer une éventuelle nouvelle intersection
				Rect_d rectRecherchePath = new Rect_d(ptG);
				int nbSegAdded = vSegmentAdded.size();
				for (int i=0 ; i<nbSegAdded ; i++) {
					Segment_d seg = vSegmentAdded.get(i);
					rectRecherchePath.extendToSeg(seg);
				}
				rectRecherchePath.expand(2*largZST, 2*largZST);// on grossit pas mal le rect compenser le fait que le SPI Path n'est pas mis a jour entre chaque realisation de pattern
				ArrayList<PathREF> vPathProche = (ArrayList) SimplifTopo.spiPath.getObjectsThatMayIntersectWith(rectRecherchePath);


				boolean bNewIntersect = SimplifTopo.isThereNewIntersection(vPathProche, vSegmentAdded, mapPortionDeleted);
				if (bNewIntersect) {
					numStrategie++;
					if (numStrategie>=3) break;
					continue;
				} else {
					bOK = true;
					break;
				}
			}

			if (!bOK) {
				Logger.log_DEBUG2(" => KO : toutes les strategies creent de nouvelles intersections ...");
				return false;
			}
			// Ici, tout est OK : on va realiser la simplification
			Logger.log_DEBUG1(" => OK pour " + j1.getMainPathContenant() + " - " + j2.getMainPathContenant());
			realisePattern(j1, j2, null, ptG, setPathSimplifies, mapPortionDeleted);

			assert(!SimplifTopo.vPtMultiple.contains(j1) && !SimplifTopo.vPtMultiple.contains(j2));
			return true;
		}
		
	}

	// fonction compatible 3-1 / 2-1
	private static boolean doesJunctionSatisfyPattern(JunctionREF j1, JunctionREF j2, Point_d ptG, double largZST, JunctionREF j3) {
		String idDuo = getIdForDuo(j1, j2);
		if (setDuoNotWorking.contains(idDuo))
			return false;
				
		ArrayList<PathREF> vPathCommun_1_2 = (ArrayList) A_Path.getCommonPath(j1, j2);
		if (vPathCommun_1_2.isEmpty()) {
			Logger.log_DEBUG2(" -> 2 des junctions ne sont pas liees par des path communs");
			setDuoNotWorking.add(idDuo);
			return false;
		}
		
		for (PathREF path : vPathCommun_1_2) {
			
			// on n'utilise pas path.getIndexOfThisJunction(j1 puis j2) car le path peut repasser 2 fois par la meme intersect
			//  on fait un traitement perso
			int indexMin = Integer.MAX_VALUE, indexMax = Integer.MIN_VALUE;
			ArrayList<JunctionREF> vJ = path.vJunctionREF;
			int nbJ = vJ.size();
			for (int i = 0; i <nbJ; i++) {
				JunctionREF j = vJ.get(i);
				if (j==j1 || j==j2) {
					indexMin = Math.min(indexMin, i);
					indexMax = Math.max(indexMax, i);
				}
			}
			assert (indexMin != Integer.MAX_VALUE && indexMax != Integer.MIN_VALUE);
			
			for (int k=indexMin+1; k<=indexMax-1; k++) {
				JunctionREF j = path.vJunctionREF.get(k);

				// correction algo >=v22 22/12/2014
				// les 2 derniers tests peuvent etre nécessaires dans certains cas
				// (ex CONNECT_3 avec 2 intersect  juste à gauche de MTER5 dans la BV 2014 n°3)
				// sans ces 2 tests, certains pattern étaient considérés comme invalides alors qu'ils le sont
				if (!j.isStd() && j != j3 && j != j1 && j != j2) {
					Logger.log_DEBUG2(" -> un des Path entre 2 des jonctions comporte autre chose que des jonctions STD");
					setDuoNotWorking.add(idDuo);
					return false;
				}
				
				if (j.distTo(ptG)>largZST) {
					Logger.log_DEBUG2(" -> un des Path entre 2 des jonctions s'eloigne trop de la Zone de Simplification");
					setDuoNotWorking.add(idDuo);
					return false;
				}
			}
		}
		return true;
	}
	
// ancienne methode trop restrictive
//	// Derniere condition a respecter pour ce pattern :
//	// Chaque path doit etre compatible avec la fusion operee par le pattern
//	//  notamment, il ne faut pas que 2 path qui avant ne se croisaient pas se retrouvent intersecter
//	//  a la fin du pattern
//	// Le test est simple, il faut chaque path passe au moins par 2 des junction du pattern ou bien
//	//  qu'il ait pour extremite l'une de ces junction
	private static boolean isPathCompatibleWithPattern(PathREF path, JunctionREF j1, JunctionREF j2, JunctionREF j3) {
		if (j1.isExtremite(path) || j2.isExtremite(path) || (j3!=null && j3.isExtremite(path)))
			return true;
		
		int nbJ = 0;
		if (j1.faitPartieDuPath(path)) nbJ++;
		if (j2.faitPartieDuPath(path)) nbJ++;
		if (j3!=null && j3.faitPartieDuPath(path)) nbJ++;
		return nbJ>=2;
	}
	

	private static boolean arePathCompatibleWithPattern(PERMISSIVITE p, JunctionREF j1, JunctionREF j2, JunctionREF j3) {
		if (p==PERMISSIVITE.TRES)
			return arePathCompatibleWithPattern_tresPermissif(j1, j2, j3);
		if (p==PERMISSIVITE.MOYENNEMENT)
			return arePathCompatibleWithPattern_moyennementPermissif(j1, j2, j3);
		if (p==PERMISSIVITE.PEU)
			return arePathCompatibleWithPattern_peuPermissif(j1, j2, j3);
		if (p==PERMISSIVITE.TRES_PEU)
			return arePathCompatibleWithPattern_trespeuPermissif(j1, j2, j3);
		return false;
	}


	private static boolean arePathCompatibleWithPattern_tresPermissif(JunctionREF j1, JunctionREF j2, JunctionREF j3) {
		return true;
	}

	// Derniere condition a respecter pour ce pattern :
	// Chaque path doit etre compatible avec la fusion operee par le pattern
	//  notamment, il ne faut pas que 2 path qui avant ne se croisaient pas se retrouvent intersectés
	//  a la fin du pattern
	// Le test est :
	//  - si 2 ou 3 CONNECT_3 parmi les 3 junctions, alors aucun souci
	//  - si 1 CONNECT_3 parmi les 3 junctions, alors on autorise 1 seule INTERSECT 'j' parmi les 2, a comporter un path la traversant et ne passant que par elle
	//  - si 3 INTERSECT, alors on autorise 1 seule INTERSECT 'j' parmi les 3, a comporter un path la traversant et ne passant que par elle
	//         mais a la condition supplementaire que les 2 autres INTERSECT aient tous leur path traversant passant par 'j'
	//  gloups ...
	// Pour ce qui est du pattern 2->1, le test est :
	//  - si 2 CONNECT_3, alors aucun souci
	//  - si 1 CONNECT_3 et 1 INTERSECT, alors aucun souci
	//  - si 2 INTERSECT, alors on a droit a une seule junction avec un path traversant non passant par l'autre
	// Attention : ces regles limites la reunion de path qui ne souhaitaient pas etre ensemble, mais cela peut encore arriver
	//  => les simplif topo sont vraiment reservee dans les zones tres denses qui poseront des souci de generalisation
	private static boolean arePathCompatibleWithPattern_moyennementPermissif(JunctionREF j1, JunctionREF j2, JunctionREF j3) {
		
		if (typePattern==PATTERN_3_1) { // ie. j3 !=null
			// suivant le nombre de connect_3, le test est plus ou moins simple
			int nbCONNECT_3 = 0;
			if (j1.isConnect3()) nbCONNECT_3++;
			if (j2.isConnect3()) nbCONNECT_3++;
			if (j3.isConnect3()) nbCONNECT_3++;
			
			if (nbCONNECT_3 >= 2)
				return true;
			
			else if (nbCONNECT_3 == 1) {
				int nbJunctionWithPathTraversantPassantQueParElle = 0;
				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, j3)) nbJunctionWithPathTraversantPassantQueParElle++;
				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, j3)) nbJunctionWithPathTraversantPassantQueParElle++;
				if (nbJunctionWithPathTraversantPassantQueParElle>=2) return false;
				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j3, j1, j2)) nbJunctionWithPathTraversantPassantQueParElle++;
				if (nbJunctionWithPathTraversantPassantQueParElle>=2) return false;
				return true;
				
			} else {
				// 3 INTERSECT, attention ca pique les yeux !
				
				int nbJunctionWithPathTraversantPassantQueParElle = 0;
				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, j3) ||
						doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, j3) ||
						doesJunctionHavePathTraversantEtNePassantQueParElle(j3, j1, j2) )
					return false;
				else
					return true;
				
//				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, j3)) {
//					// Arrive la, il FAUT que les path traversant les 2 autres junctions passent forcement par 'j'
//					if (doesAllPathTraversantAutreJunctionPasseParJ(j1, j2, j3))
//						return true; // on peut arreter la recherche, on est sur que les 2 autres junction n'ont pas de path traversant ne passant que par elles
//					else
//						return false;
//				}
//				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, j3)) {
//					// Arrive la, il FAUT que les path traversant les 2 autres junctions passent forcement par 'j'
//					if (doesAllPathTraversantAutreJunctionPasseParJ(j2, j1, j3))
//						return true; // on peut arreter la recherche, on est sur que la derniere junction n'a pas de path traversant ne passant que par elles
//					else
//						return false;
//				}
//				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j3, j1, j2)) {
//					// Arrive la, il FAUT que les path traversant les 2 autres junctions passent forcement par 'j'
//					if (doesAllPathTraversantAutreJunctionPasseParJ(j3, j1, j2))
//						return true;
//					else
//						return false;
//				}
//				return true;
			}

			
		} else {
			assert (j3==null);
			// suivant le nombre de connect_3, le test est plus ou moins simple
			if (j1.isConnect3() && j2.isConnect3())
				return true;

			// 1 intersect + 1 connect_3
			if (j1.isConnect3() || j2.isConnect3())
				return true;

			if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, null) || doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, null))
				return false;
			else
				return true;
//			}
//			
//			// ici on a 2 INTERSECT
//			if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, null)) {
//				if (doesAllPathTraversantAutreJunctionPasseParJ(j1, j2, null))
//					return true; // on peut arreter la recherche, on est sur que l'autres junction n'a pas de path traversant ne passant que par elle
//				else
//					return false;
//			}
//			if (doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, null)) {
//				if (doesAllPathTraversantAutreJunctionPasseParJ(j2, j1, null))
//					return true;
//				else
//					return false;
//			}
//			return true;
		}
	}

	private static boolean arePathCompatibleWithPattern_peuPermissif(JunctionREF j1, JunctionREF j2, JunctionREF j3) {

		if (typePattern==PATTERN_3_1) { // ie. j3 !=null
			// suivant le nombre de connect_3, le test est plus ou moins simple
			int nbCONNECT_3 = 0;
			if (j1.isConnect3()) nbCONNECT_3++;
			if (j2.isConnect3()) nbCONNECT_3++;
			if (j3.isConnect3()) nbCONNECT_3++;

			if (nbCONNECT_3 == 3)
				return true;

			else {
				// au moins 1 intersect

				//1er critère
				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, j3) ||
						doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, j3) ||
						doesJunctionHavePathTraversantEtNePassantQueParElle(j3, j1, j2) )
					return false;

				//2ème critère
				int nbIntersectAvecPathExtremite = 0;
				if (j1.isIntersect() && dosesIntersectHavePathExtremite(j1)) nbIntersectAvecPathExtremite++;
				if (j2.isIntersect() && dosesIntersectHavePathExtremite(j2)) nbIntersectAvecPathExtremite++;
				if (j3.isIntersect() && dosesIntersectHavePathExtremite(j3)) nbIntersectAvecPathExtremite++;
				if (nbIntersectAvecPathExtremite>=2)
					return false;

				return true;
			}


		} else { // PATTERN_2_1
			assert (j3==null);
			// suivant le nombre de connect_3, le test est plus ou moins simple
			if (j1.isConnect3() && j2.isConnect3())
				return true;

			// 1 intersect + 1 connect_3
			if (j1.isConnect3() || j2.isConnect3())
				return true;

			// 2 intersect

			// 1er critère
			if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, null) || doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, null))
				return false;

			// 2eme critere
			int nbIntersectAvecPathExtremite = 0;
			if (j1.isIntersect() && dosesIntersectHavePathExtremite(j1)) nbIntersectAvecPathExtremite++;
			if (j2.isIntersect() && dosesIntersectHavePathExtremite(j2)) nbIntersectAvecPathExtremite++;
			if (nbIntersectAvecPathExtremite>=2)
				return false;
			
			return true;
		}
	}

	private static boolean arePathCompatibleWithPattern_trespeuPermissif(JunctionREF j1, JunctionREF j2, JunctionREF j3) {

		if (typePattern==PATTERN_3_1) { // ie. j3 !=null

			// Il ne doit y avoir aucune jonction avec un path traversant et ne passant que par elle
			//  on considère qu'un path est traversant si il l'est rellement (cas des intersect)
			//  ou bien si la jonction a au moins 2 path extrémités (intersect ou connect_3)
			int nbJuncAvecPathTraversantNePassantQueParElle = 0;

			if (doesJunctionHavePathTraversantEtNePassantQueParElle_etendu(j1, j2, j3) ||
				doesJunctionHavePathTraversantEtNePassantQueParElle_etendu(j2, j1, j3) ||
				doesJunctionHavePathTraversantEtNePassantQueParElle_etendu(j3, j1, j2))
				return false;
			else
				return true;



/*			// suivant le nombre de connect_3, le test est plus ou moins simple
			int nbCONNECT_3 = 0;
			if (j1.isConnect3()) nbCONNECT_3++;
			if (j2.isConnect3()) nbCONNECT_3++;
			if (j3.isConnect3()) nbCONNECT_3++;

			if (nbCONNECT_3 == 3)
				return true;

			else {
				// au moins 1 intersect

				// 1er critère
				if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, j3) ||
						doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, j3) ||
						doesJunctionHavePathTraversantEtNePassantQueParElle(j3, j1, j2) )
					return false;

				// 2ème critère
				int nbIntersectAvecPathExtremite = 0;
				if (j1.isIntersect() && dosesIntersectHavePathExtremite(j1)) nbIntersectAvecPathExtremite++;
				if (j2.isIntersect() && dosesIntersectHavePathExtremite(j2)) nbIntersectAvecPathExtremite++;
				if (j3.isIntersect() && dosesIntersectHavePathExtremite(j3)) nbIntersectAvecPathExtremite++;
				if (nbIntersectAvecPathExtremite>=1) // <> PEU_PERMISSIF
					return false;

				// <> PEU_PERMISSIF
				// 3ème critère : les CONNECT_3 ne doivent avoir que 3 path maxi reliés (evite souci type nord de ARPAJ)
				if (j1.isConnect3() && j1.getNbPathContenant()>3) return false;
				if (j2.isConnect3() && j2.getNbPathContenant()>3) return false;
				if (j3.isConnect3() && j3.getNbPathContenant()>3) return false;

				return true;
			}
*/

		} else { // PATTERN_2_1
			assert (j3==null);

			// Il ne doit y avoir qu'une seule jonction avec un path traversant et ne passant que par elle
			//  on considère qu'un path est traversant si il l'est rellement (cas des intersect)
			//  ou bien si la jonction a au moins 2 path extrémités (intersect ou connect_3
			if (doesJunctionHavePathTraversantEtNePassantQueParElle_etendu(j1, j2, null) &&
				doesJunctionHavePathTraversantEtNePassantQueParElle_etendu(j2, j1, null))
				return false;
			else
				return true;
/*
			// suivant le nombre de connect_3, le test est plus ou moins simple
			if (j1.isConnect3() && j2.isConnect3())
				return true;

			// au moins 1 intersect

			// 1er critère
			if (doesJunctionHavePathTraversantEtNePassantQueParElle(j1, j2, null) || doesJunctionHavePathTraversantEtNePassantQueParElle(j2, j1, null))
				return false;

			// 2eme critere
			int nbIntersectAvecPathExtremite = 0;
			if (j1.isIntersect() && dosesIntersectHavePathExtremite(j1)) nbIntersectAvecPathExtremite++;
			if (j2.isIntersect() && dosesIntersectHavePathExtremite(j2)) nbIntersectAvecPathExtremite++;
			if (nbIntersectAvecPathExtremite>=1) // <> PEU_PERMISSIF
				return false;

			// <> PEU_PERMISSIF
			// 3ème critère : les CONNECT_3 ne doivent avoir que 3 path maxi reliés (evite souci type nord de OLLAI)
			if (j1.isConnect3() && j1.getNbPathContenant()>2) return false;
			if (j2.isConnect3() && j2.getNbPathContenant()>2) return false;

			return true;
 */
		}
	}

	// Notion étendue de "path traversant"
	//   fonction compatible 3->1 / 2->1
	private static boolean doesJunctionHavePathTraversantEtNePassantQueParElle_etendu(JunctionREF j, JunctionREF j_autre1, JunctionREF j_autre2) {

		// Path traversant "normaux"
		for (A_Path path : j.getVPathContenant_traversant()) {
			if (!j_autre1.faitPartieDuPath(path) && (j_autre2==null || !j_autre2.faitPartieDuPath(path)))
				return true;
		}
		// Path traversant "étendus"
		int nbPathEtenduTraversant = 0;
		for (A_Path path : j.getVPathContenant_nonTraversant()) {
			if (!j_autre1.faitPartieDuPath(path) && (j_autre2==null || !j_autre2.faitPartieDuPath(path)))
				nbPathEtenduTraversant++;
		}
		if (nbPathEtenduTraversant>=2)
			return true;

		return false;
	}

	// TODO_ABANDONNE v17 OPTIM j peut etre un connect_3 dans le pattern 3->1
	private static boolean doesJunctionHavePathTraversantEtNePassantQueParElle(JunctionREF j, JunctionREF j_autre1, JunctionREF j_autre2) {
		if (j_autre2 != null) {
			for (A_Path path : j.getVPathContenant())
				if (!j.isExtremite(path) && !j_autre1.faitPartieDuPath(path) && !j_autre2.faitPartieDuPath(path))
					return true;
			return false;
		} else {
			for (A_Path path : j.getVPathContenant())
			if (!j.isExtremite(path) && !j_autre1.faitPartieDuPath(path))
				return true;
			return false;
		}
	}
	private static boolean doesAllPathTraversantAutreJunctionPasseParJ(JunctionREF j, JunctionREF j_autre1, JunctionREF j_autre2) {
		for (A_Path path : j_autre1.getVPathContenant()) {
			if (!j_autre1.isExtremite(path) && !j.faitPartieDuPath(path))
				return false;
		}
		if (j_autre2 == null)
			return true;
		
		for (A_Path path : j_autre2.getVPathContenant()) {
			if (!j_autre2.isExtremite(path) && !j.faitPartieDuPath(path))
				return false;
		}
		// arrive ici, tout est OK
		return true;
	}

	private static boolean dosesIntersectHavePathExtremite(JunctionREF j) {
		return j.getVPathContenant_nonTraversant().size()>0;
	}
	
	
	
	static int PROCHE_PATTERN = 1;
	// Determine les segments qui seraient ajoutes et les portion de path qui seraient supprimees
	//  si on realisait le pattern
	private static void computeNewAndDeletedSegment(PathREF path, JunctionREF j1, JunctionREF j2,JunctionREF j3, Point_d ptG,
						ArrayList<Segment_bound> vSegmentAdded, HashMap<PathREF,SimplifTopo.PortionPath> mapPortionDeleted) {
		
		//*********************************************************************************************
		// La portion de path à supprimer est la partie entre tous les pt multiples + les points encadrant (s'ils existent)
		
		// donc on commence par déterminer les index min et max des n pt multiples pour ce path
		// on n'utilise pas path.getIndexOfThisJunction(j1 puis j2 puis j3) car le path peut repasser 2 fois par la meme intersect
		//  on fait un traitement perso
		int indexMin = Integer.MAX_VALUE, indexMax = Integer.MIN_VALUE;
		ArrayList<JunctionREF> vJ = path.vJunctionREF;
		int nbJ = vJ.size();
		for (int i = 0; i <nbJ; i++) {
			JunctionREF j = vJ.get(i);
			if (j==j1 || j==j2 || j==j3) {
				indexMin = Math.min(indexMin, i);
				indexMax = Math.max(indexMax, i);
			}
		}
		assert (indexMin != Integer.MAX_VALUE && indexMax != Integer.MIN_VALUE);
		
		// On supprime a partir des junctions encadrant les pt multiples
		boolean isIndex1ADeletedJunction=false, isIndex2ADeletedJunction=false;
		if (indexMin > 0)
			indexMin--;
		else
			isIndex1ADeletedJunction = true;
		
		if (indexMax < nbJ-1)
			indexMax++;
		else
			isIndex2ADeletedJunction = true;

		SimplifTopo.PortionPath portionPathASupprimer = new SimplifTopo.PortionPath(path, indexMin, indexMax, isIndex1ADeletedJunction, isIndex2ADeletedJunction);
		mapPortionDeleted.put(path, portionPathASupprimer);
		
		
		//*********************************************************************************************
		// Les segments à ajouter sont entre les encadrants et le barycentre
		int nbSegAjoute = 0;
		if (!isIndex1ADeletedJunction) {
			JunctionREF j_encadr = path.vJunctionREF.get(indexMin);
			JunctionREF j_deleted = path.vJunctionREF.get(indexMin+1);
			Point_d pt_interm = new Point_d((j_encadr.x + PROCHE_PATTERN*j_deleted.x)/(PROCHE_PATTERN+1), (j_encadr.y + PROCHE_PATTERN*j_deleted.y)/(PROCHE_PATTERN+1));
			vSegmentAdded.add(new Segment_bound(j_encadr, pt_interm));
			vSegmentAdded.add(new Segment_bound(pt_interm, ptG));
			nbSegAjoute+=2;
		}
		if (!isIndex2ADeletedJunction) {
			JunctionREF j_encadr = path.vJunctionREF.get(indexMax);
			JunctionREF j_deleted = path.vJunctionREF.get(indexMax-1);
			Point_d pt_interm = new Point_d((j_encadr.x + PROCHE_PATTERN*j_deleted.x)/(PROCHE_PATTERN+1), (j_encadr.y + PROCHE_PATTERN*j_deleted.y)/(PROCHE_PATTERN+1));
			vSegmentAdded.add(new Segment_bound(ptG, pt_interm));
			vSegmentAdded.add(new Segment_bound(pt_interm, j_encadr));
			nbSegAjoute+=2;
		}
		
		Logger.log_DEBUG2(" -> Path " + path + " : portion à supprimer: " + portionPathASupprimer.index1 + " -> " + portionPathASupprimer.index2 +
				"  nbSeg ajoutés = " + nbSegAjoute);
		if (portionPathASupprimer.pathToBeSuppressed())
			Logger.log_DEBUG2("    -> A SUPPRIMER !");
	}
	

	private static void realisePattern(JunctionREF j1, JunctionREF j2, JunctionREF j3, Point_d ptG, THashSet<PathREF> setPathSimplifies, HashMap<PathREF, SimplifTopo.PortionPath> mapPortionDeleted) {
		// Nouvelle Junction barycentre
		// La plupart du temps, ce sera une INTERSECT, mais ca peut aussi etre un CONNECT_3 voire CONNECT_2 -> on determinera son type a la fin
		JunctionREF jG = new JunctionREF(ptG, A_Junction.TypeJunction.NOT_SET);
		jG.addInfoDebug("barycentre cree par Pattern 3ptMult->1");
		
		// on recupere la moyenne des complexites de zone des ptMultiple qui disparaissent
		if (j3!=null)
			jG.complexiteZone = (j1.complexiteZone + j2.complexiteZone + j3.complexiteZone) / 3;
		else
			jG.complexiteZone = (j1.complexiteZone + j2.complexiteZone) / 2;
		
		ArrayList<PathREF> vPathToRemove = new ArrayList<PathREF>();
		
		for (PathREF path : setPathSimplifies) {
			
			// Portion du path qui avait ete determinee comme etant a supprimer lors des tests precedents
			SimplifTopo.PortionPath portionToDelete = mapPortionDeleted.get(path);
			assert(portionToDelete != null);
			
			// Cas special si le path doit etre completement supprime
			if (portionToDelete.pathToBeSuppressed()) {
				vPathToRemove.add(path);
				continue;
			}
			
			// Cas normal : on doit supprimer une partie du path et ajouter de nouveaux segments
			// Pour faire simple, on recree completement le vecteur de junctions du path
			ArrayList<JunctionREF> vJREF_old = path.vJunctionREF;
			ArrayList<JunctionREF> vJREF_new = new ArrayList<JunctionREF>();

			if (!mapPathInitialRect.containsKey(path))
				mapPathInitialRect.put(path, path.getRectEmprise());

			
			int nbJ_old = vJREF_old.size();
			for (int i = 0; i < nbJ_old; i++) {
				JunctionREF j = vJREF_old.get(i);
				
				// Avant l'extremite 1 de la portion a supprimer
				if (i<portionToDelete.index1) {
					vJREF_new.add(j);
				}
				
				// Extremite 1 de la portion a supprimer
				else if (i==portionToDelete.index1) {
					// debut de la portion a supprimer : on l'ajoute
					if (!portionToDelete.isIndex1ADeletedJunction) {
						vJREF_new.add(j);
						
						// ajout d'un point intermediaire pour eviter la superposition de segment dans certains cas
						JunctionREF j_next = vJREF_old.get(i+1);
						JunctionREF j_interm = new JunctionREF((j.x + PROCHE_PATTERN*j_next.x)/(PROCHE_PATTERN+1), (j.y + PROCHE_PATTERN*j_next.y)/(PROCHE_PATTERN+1), A_Junction.TypeJunction.STD, path);
						j_interm.addInfoDebug("pt intermediaire cree par Pattern 3PtMult->1");
						vJREF_new.add(j_interm);
						SimplifTopo.vJunctionREF.add(j_interm);
					}
					else {
						j.removePathContenant(path); // pas necessaire puisque la junction va etre supprimee, mais bon...
						//j.addInfoDebug("=> censée etre supprimée !!!!");
					}
					
					// puis le barycentre
					vJREF_new.add(jG);
					jG.addPathContenant(path);
				}
				
				// Entre les 2 extremites de la portion a supprimer
				else if (i<portionToDelete.index2) {
					j.removePathContenant(path); // pas necessaire puisque la junction va etre supprimee, mais bon...
					//j.addInfoDebug("=> censée etre supprimée !!!!");
				}
				
				// Extremite 2 de la portion a supprimer
				else if (i==portionToDelete.index2) {
					if (!portionToDelete.isIndex2ADeletedJunction) {
						
						// ajout d'un point intermediaire pour eviter la superposition de segment dans certains cas
						JunctionREF j_prev = vJREF_old.get(i-1);
						JunctionREF j_interm = new JunctionREF((j.x + PROCHE_PATTERN*j_prev.x)/(PROCHE_PATTERN+1), (j.y + PROCHE_PATTERN*j_prev.y)/(PROCHE_PATTERN+1), A_Junction.TypeJunction.STD, path);
						j_interm.addInfoDebug("pt intermediaire cree par Pattern 3PtMult->1");
						vJREF_new.add(j_interm);
						SimplifTopo.vJunctionREF.add(j_interm);
						
						vJREF_new.add(j);
					}
					else {
						j.removePathContenant(path); // pas necessaire puisque la junction va etre supprimee, mais bon...
						//j.addInfoDebug("=> censée etre supprimée !!!!");
					}
				}
				
				// Apres l'extremite 2 de la portion a supprimer
				else {
					vJREF_new.add(j);
				}
			}
			
			path.vJunctionREF = vJREF_new;
						
			// On indique le path comme ayant ete modifies par l'algo
			SimplifTopo.vPathREF_modified.add(path);
			
		}
		
		//****************************************************************************
		// Une fois tout ca realise, il faut remettre de l'ordre dans les donnees
		
		// 1) Determiner le type du barycentre
		jG.majTypeJunction();
		
		// 2) Maintenant, grand menage dans le vecteur global de path et de junctions
		for (PathREF path : vPathToRemove) {
			SimplifTopo.vPathREF.remove(path);
			// attention, si le path fait partie des path modified car deja impliqué dans un precedent pattern realise
			// il faut l'enlever, car sinon, on va le donner à manger au simplificateur de path et notamment
			// il sera sous-decoupé, et on va alors créer des junctions appartenant a un path supprime ! (va suivre alors une serie de bug tres genants)
			SimplifTopo.vPathREF_modified.remove(path);
		}
		
		SimplifTopo.vJunctionREF.add(jG);
		// !! Attention, a ce stade on ne nettoie pas le vecteur global de junction
		// on ne le fera qu'en fin de traitement, par souci d'optimisation
//		JunctionREF.cleanVJunctionREFGlobal(SimplifTopo.vPathREF, SimplifTopo.vJunctionREF);
		// par contre, on reconstitue le sous-ensemble de données "pt multiple"
		SimplifTopo.reinitDataPtMultiple();
		
		// le spi path est long a realimenter, on va se contenter de supprimer les path
		// pour ce qui est des path qui ont ete deforme par le pettern, cette deformation est minime et compensee par des recherche sur des rect plus larges
		//SimplifTopo.spiPath.clear();
		//SimplifTopo.spiPath.addObjects (SimplifTopo.vPathREF);
		for (PathREF path : vPathToRemove)
			// si le path n'a jamais ete modifie, la map renverra null, et le SPI prendra le rectEnglobant courant du path, donc c'est OK
			SimplifTopo.spiPath.removeObject(path, mapPathInitialRect.get(path));
	}

	// l'ID du trio ne doit pas dependre de l'ordre des junctions -> on tri leur id
	private static String getIdForTrio(JunctionREF j1, JunctionREF j2, JunctionREF j3) {
		if (j1.id < j2.id) {
			if (j1.id < j3.id) {
				if (j2.id < j3.id)
					return j1.id + "-" + j2.id + "-" + j3.id;
				else
					return j1.id + "-" + j3.id + "-" + j2.id;
			} else {
				return j3.id + "-" + j1.id + "-" + j2.id;
				
			}
		} else {
			if (j2.id < j3.id) {
				if (j1.id < j3.id)
					return j2.id + "-" + j1.id + "-" + j3.id;
				else
					return j2.id + "-" + j3.id + "-" + j1.id;
			} else {
				return j3.id + "-" + j2.id + "-" + j1.id;
				
			}
		}
	}

	private static String getIdForDuo(JunctionREF j1, JunctionREF j2) {
		if (j1.id < j2.id)
			return j1.id + "-" + j2.id;
		else
			return j2.id + "-" + j1.id;
	}
	
//	
//	
//	
//	private static class CombinaisonPattern implements Comparable<CombinaisonPattern> {
//		public ArrayList<JunctionREF> vJ;
//		public double largZST; // largeur de la ZST = max des largeurs des n ptMultiple
//		public double rayonPattern_sq=-1; // ce rayon ne sert qu'a trier les pattern du plus petit au plus grand
//		public void addJ(JunctionREF j) {
//			if (vJ==null) vJ=new ArrayList<JunctionREF>();
//			vJ.add(j);
//			largZST = Math.max(largZST, j.getLargestPathContenant()*SimplifTopo.params.factor_SimplifTopo);
//		}
//		@Override
//		public int compareTo(CombinaisonPattern c2) {
//			if (this.rayonPattern_sq<0) this.computeRayonPattern();
//			if (c2.rayonPattern_sq<0) c2.computeRayonPattern();
//			return Double.compare(this.rayonPattern_sq, c2.rayonPattern_sq);
//		}
//
//		private void computeRayonPattern() {
//			double xG=0, yG=0;
//			for (JunctionREF j : vJ) {
//				xG += j.x;
//				yG += j.y;
//			}
//			for (JunctionREF j : vJ)
//				rayonPattern_sq = Math.max(rayonPattern_sq, (xG-j.x)*(xG-j.x) + (yG-j.y)*(yG-j.y));
//		}
//	}
	 

}
